package com.developer.platform.domain.service.impl;

import static com.developer.platform.RedisConstant.AUTHORIZING_KEY;

import cn.hutool.core.bean.BeanUtil;
import com.developer.platform.domain.Menu;
import com.developer.platform.domain.factory.LoginFactory;
import com.developer.platform.domain.security.AuthenticationInfo;
import com.developer.platform.domain.security.AuthorizationInfo;
import com.developer.platform.domain.security.UserDetails;
import com.developer.platform.domain.service.IAuthorizingRealm;
import com.developer.platform.domain.service.IMenuService;
import com.developer.platform.infrastructure.error.SecurityErrorType;
import com.veeker.core.exceptions.BusinessException;
import com.veeker.redis.utils.RedisUtil;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;

/**
 * @author ：qiaoliang
 * @date ：2020-11-09
 */
@Service
public class AuthorizingRealm implements IAuthorizingRealm {

    private final IMenuService menuService;
    private final LoginFactory loginFactory;

    public AuthorizingRealm(IMenuService menuService,
                            LoginFactory loginFactory) {
        this.menuService = menuService;
        this.loginFactory = loginFactory;
    }

    @Override
    public List<AuthorizationInfo> doGetAuthorizationInfo(Authentication authenticationInfo) {
        BusinessException.isFalse(authenticationInfo.isAuthenticated(), SecurityErrorType.NO_ACCESS_ERROR);

        UserDetails userDetails = (UserDetails)authenticationInfo.getPrincipal();
        String key = String.valueOf(userDetails.getId());
        Object value = RedisUtil.hashGet(AUTHORIZING_KEY, key);
        List<AuthorizationInfo> authorizationInfos;
        if(Objects.nonNull(value)){
            authorizationInfos = (List<AuthorizationInfo>)value;
        }else {
            List<Menu> list = menuService.usersCanAccessResources(userDetails.getId());
            authorizationInfos = list.stream()
                    .map(l -> {
                        AuthorizationInfo authorizationInfo = new AuthorizationInfo();
                        BeanUtil.copyProperties(l, authorizationInfo);
                        return authorizationInfo;
                    })
                    .collect(Collectors.toList());
            RedisUtil.hashsSet(AUTHORIZING_KEY, key, authorizationInfos);
        }
        return authorizationInfos;
    }

    @Override
    public Authentication doGetAuthenticationInfo(Authentication authentication) {
        AuthenticationInfo authenticationInfo = (AuthenticationInfo)authentication;
        return loginFactory.handle(authenticationInfo.getLoginType()).login(authenticationInfo.getPrincipal(),
                authenticationInfo.getCredentials());
    }

    @Override
    public void initializationResourceDefine() {
        RedisUtil.delete(AUTHORIZING_KEY);
    }

}
